#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QFontDatabase>
#include "textedit.h"
#include <QMdiSubWindow>
#include <QFileDialog>
#include <QFileInfo>
#include <QPrinter>
#include <QPrintDialog>
#include <QPrintPreviewDialog>
#include <QCloseEvent>
#include <QColorDialog>
#include <QTextCharFormat>
#include <QTextCursor>
#include <QDebug>
#include <QTextList>

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    init();
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::init()
{
    ui->mdiArea->setBackground(QBrush(Qt::white));
    initFontSize();         //初始化字号
    initScrollBar();        //初始化滚动条
    initWindowAction();     //初始化窗体相关action

    //subWindowActivated当窗口被激活后发出这个信号
    //窗体关闭时也会发出这个信号，且信号参数为0
    connect(ui->mdiArea, &QMdiArea::subWindowActivated, this, &MainWindow::initWindowAction);

    initDocAction();        //初始化文本相关action

    actionGroup = new QActionGroup(this);
    actionGroup->setExclusive(true);       //排他的
    mapper = new QSignalMapper(this);

    //aboutToShow在菜单显示给用户之前发出
    connect(ui->menu_W, &QMenu::aboutToShow, this, &MainWindow::addSubWindowAction);
    connect(mapper, SIGNAL(mapped(QWidget*)), this, SLOT(setActiveSubWindow(QWidget*)));
}

void MainWindow::initFontSize()
{
    ui->sizeComboBox->clear();

    //QFontDatabase提供系统可用字体的相关信息
    for(int fontSize : QFontDatabase::standardSizes())     //返回标准字体大小的列表
    {
        ui->sizeComboBox->addItem(QString::number(fontSize));     //字号插入comboBox
    }

    //初始化字号组合框的当前选择项
    QFont appFont = QApplication::font();    //当前系统默认字体
    int fontSize = appFont.pointSize();  //字体号

    int sizeIndex = ui->sizeComboBox->findText(QString::number(fontSize));

    ui->sizeComboBox->setCurrentIndex(sizeIndex);
}

void MainWindow::initScrollBar()
{
    //设置水平垂直滚动条策略
    ui->mdiArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded);
    ui->mdiArea->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
}

void MainWindow::initWindowAction()
{
    bool hasActWindow = (activateWindow() != nullptr);
    ui->saveAction->setEnabled(hasActWindow);
    ui->saveAsAction->setEnabled(hasActWindow);
    ui->printAction->setEnabled(hasActWindow);
    ui->printViewAction->setEnabled(hasActWindow);
    ui->undoAction->setEnabled(hasActWindow);
    ui->redoAction->setEnabled(hasActWindow);
    ui->pasteAction->setEnabled(hasActWindow);
    ui->closeAction->setEnabled(hasActWindow);
    ui->closeAllAction->setEnabled(hasActWindow);
    ui->tileAction->setEnabled(hasActWindow);
    ui->cascadeAction->setEnabled(hasActWindow);
    ui->nextAction->setEnabled(hasActWindow);
    ui->previousAction->setEnabled(hasActWindow);
}

void MainWindow::initDocAction()
{
    ui->cutAction->setEnabled(false);
    ui->copyAction->setEnabled(false);
    ui->colorAction->setEnabled(false);
    ui->blodAction->setEnabled(false);
    ui->italicAction->setEnabled(false);
    ui->underLineAction->setEnabled(false);
    ui->leftAlignAction->setEnabled(false);
    ui->centerAction->setEnabled(false);
    ui->rightAlignAction->setEnabled(false);
    ui->justifyAction->setEnabled(false);
}

TextEdit *MainWindow::activateWindow()
{
    QMdiSubWindow* window = ui->mdiArea->activeSubWindow();   //保存当前活动窗口
    if(window)
    {
        return qobject_cast<TextEdit*>(window->widget());     //返回QMdiSubWindow中内嵌的小部件
    }

    return nullptr;
}

void MainWindow::setActionStatus(bool b)
{
    ui->cutAction->setEnabled(b);
    ui->copyAction->setEnabled(b);
    ui->colorAction->setEnabled(b);
    ui->blodAction->setEnabled(b);
    ui->italicAction->setEnabled(b);
    ui->underLineAction->setEnabled(b);
    ui->leftAlignAction->setEnabled(b);
    ui->centerAction->setEnabled(b);
    ui->rightAlignAction->setEnabled(b);
    ui->justifyAction->setEnabled(b);
}

void MainWindow::on_newAction_triggered()
{
    TextEdit* edit = new TextEdit;
    ui->mdiArea->addSubWindow(edit);  //TextEdit父对象将是QMdiArea的viewport小部件

    //copyAvailable当在文本编辑器中选中或取消选中文本时，会发出此信号
    connect(edit, &TextEdit::copyAvailable, this, &MainWindow::setActionStatus);
    edit->initNewDoc();
    edit->show();
}

void MainWindow::on_openAction_triggered()
{
    //返回用户选择的现有文件
    QString docName = QFileDialog::getOpenFileName(this, "打开文档", "../", "所有文件(*.*)");
    if(!docName.isEmpty())
    {
        QMdiSubWindow* sub = findSubWindow(docName);
        if(sub)      //如果有子窗体打开对应的文档
        {
            ui->mdiArea->setActiveSubWindow(sub);
            return;
        }

        TextEdit* edit = new TextEdit;
        ui->mdiArea->addSubWindow(edit);

        //copyAvailable当在文本编辑器中选中或取消选中文本时，会发出此信号
        connect(edit, &TextEdit::copyAvailable, this, &MainWindow::setActionStatus);

        if(edit->loadDoc(docName))
        {
            statusBar()->showMessage("文档已打开", 3000);   //3000ms
            edit->show();
        }
        else
        {
            edit->close();
        }
    }
}

QMdiSubWindow *MainWindow::findSubWindow(const QString &docName)
{
    QString filePath = QFileInfo(docName).canonicalFilePath();    //返回文件的绝对路径
    for(QMdiSubWindow* sub : ui->mdiArea->subWindowList())
    {
        TextEdit* edit = qobject_cast<TextEdit*>(sub->widget());
        if(edit->getDocFilePath() == filePath)
        {
            return sub;
        }
    }
    return nullptr;
}

void MainWindow::addSubWindowAction()
{
    QList<QAction*> actionList = actionGroup->actions();
    if(!actionList.isEmpty())    //如果actionGroup不为空
    {
        for(QAction* action : actionList)   //释放掉所有组内action
        {
            delete action;
        }
    }

    QList<QMdiSubWindow*> subWindowList = ui->mdiArea->subWindowList();   //获取子窗体列表
    if(!subWindowList.isEmpty()) ui->menu_W->addSeparator();     //添加一个分隔符

    for(int i = 0; i < subWindowList.count(); i++)
    {
        QMdiSubWindow* subWindow = subWindowList[i];
        TextEdit* edit = qobject_cast<TextEdit*>(subWindow->widget());   //获取内嵌部件

        QString action_text = QString("%1 %2").arg(i + 1).arg(edit->getDocWindowTitle());     //action文本
        QAction* action = ui->menu_W->addAction(action_text);
        actionGroup->addAction(action);
        action->setCheckable(true);
        if(edit == activateWindow()) action->setChecked(true);     //对应活动窗体action设置为选中

        //在Qt开发中可能会遇到一种情况，就是很多个相同的信号关联同一个槽函数
        //如果我们一个一个的连接则会显得代码特别累赘，这时候我们就可以使用Qt的信号映射器
        //它的功能就是将很多个相同的信号(部件要为相同类型)’捆绑‘起来然后和一个槽函数进行关联，它可以自动识别信号发送者

        //将action的triggered信号传递给信号映射器mapper，然后由mapper统一转发
        connect(action, SIGNAL(triggered(bool)), mapper, SLOT(map()));
        mapper->setMapping(action, subWindow);   // 添加映射，设置信号发送对象与要发送的参数
    }
}

void MainWindow::on_saveAction_triggered()
{
    TextEdit* edit = activateWindow();
    if(edit)
    {
        if(edit->saveDoc())
        {
            statusBar()->showMessage("保存成功", 3000);
        }
    }
}

void MainWindow::on_saveAsAction_triggered()
{
    TextEdit* edit = activateWindow();
    if(edit)
    {
        if(edit->saveAsDoc())
        {
            statusBar()->showMessage("保存成功", 3000);
        }
    }
}

void MainWindow::on_printAction_triggered()
{
    TextEdit* edit = activateWindow();
    if(!edit) return;

    //QPrinter用于在打印机上绘图
    //QPrinter::HighResolution 将printer分辨率设置为正在使用的打印机的分辨率
    QPrinter printer(QPrinter::HighResolution);

    //QPrintDialog类提供了一个用于指定打印机配置的对话框
    QPrintDialog dialog(&printer, this);
//    dialog.setOption(QAbstractPrintDialog::PrintSelection, true);      //启用打印选定内容选项
//    printer.setPrintRange(QPrinter::Selection);      //设置打印范围，打印选定的文本

    if(dialog.exec() == QDialog::Accepted)
    {
        edit->print(&printer);
    }
}

void MainWindow::on_printViewAction_triggered()
{
    TextEdit* edit = activateWindow();
    if(!edit) return;

    QPrinter printer;
    //QPrintPreviewDialog用于预览和配置打印机输出的页面布局
    QPrintPreviewDialog preview(&printer, this);

    //当QPrintPreviewDialog需要生成一组预览页面时，就会发出这个信号
    connect(&preview, &QPrintPreviewDialog::paintRequested, this, &MainWindow::printPreview);

    if(preview.exec() == QDialog::Accepted)
    {
        edit->print(&printer);
    }
}

void MainWindow::printPreview(QPrinter *printer)
{
    TextEdit* edit = activateWindow();
    if(edit)
    {
        edit->print(printer);
    }
}

void MainWindow::on_undoAction_triggered()
{
    TextEdit* edit = activateWindow();
    if(edit)
    {
        edit->undo();
    }
}

void MainWindow::on_redoAction_triggered()
{
    TextEdit* edit = activateWindow();
    if(edit)
    {
        edit->redo();
    }
}

void MainWindow::on_pasteAction_triggered()
{
    TextEdit* edit = activateWindow();
    if(edit)
    {
        edit->paste();
    }
}

void MainWindow::on_cutAction_triggered()
{
    TextEdit* edit = activateWindow();
    if(edit)
    {
        edit->cut();
    }
}

void MainWindow::on_copyAction_triggered()
{
    TextEdit* edit = activateWindow();
    if(edit)
    {
        edit->copy();
    }
}

void MainWindow::closeEvent(QCloseEvent *event)
{
    ui->mdiArea->closeAllSubWindows();    //尝试关闭所有子窗体
    if(ui->mdiArea->currentSubWindow())   //如果有子窗体仍未关闭
    {
        event->ignore();   //忽略此关闭事件
    }
    else
    {
        event->accept();
    }
}

void MainWindow::on_exitAction_triggered()
{
    this->close();
}

void MainWindow::on_closeAction_triggered()
{
    ui->mdiArea->closeActiveSubWindow();     //关闭活动子窗体
}

void MainWindow::on_closeAllAction_triggered()
{
    ui->mdiArea->closeAllSubWindows();      //关闭所有子窗体
}

void MainWindow::on_tileAction_triggered()
{
    ui->mdiArea->tileSubWindows();          //平铺
}

void MainWindow::on_cascadeAction_triggered()
{
    ui->mdiArea->cascadeSubWindows();       //层叠
}

void MainWindow::on_nextAction_triggered()
{
    ui->mdiArea->activateNextSubWindow();    //将下一个子窗口设置为活动窗口
}

void MainWindow::on_previousAction_triggered()
{
    ui->mdiArea->activatePreviousSubWindow();   //将前一个子窗口设置为活动窗口
}

void MainWindow::setActiveSubWindow(QWidget *widget)
{
    if(widget) ui->mdiArea->setActiveSubWindow(qobject_cast<QMdiSubWindow*>(widget));
}

void MainWindow::on_colorAction_triggered()
{
    TextEdit* edit = activateWindow();
    if(edit)
    {
        QColor color = QColorDialog::getColor();
        if(!color.isValid()) return;       //颜色不合法

        QTextCharFormat format;         //为字符提供格式信息
        format.setForeground(color);    //设置前景色

        edit->mergeCurrentCharFormat(format);    //对选中文本合并字符属性格式

        QPixmap pixmap(16, 16);
        pixmap.fill(color);
        ui->colorAction->setIcon(pixmap);
    }
}

void MainWindow::on_blodAction_triggered()
{
    TextEdit* edit = activateWindow();
    if(edit)
    {
//        int start = edit->textCursor().selectionStart();
//        int end = edit->textCursor().selectionEnd();
//        for(int pos = start; pos < end; pos++)
//        {
//            edit->textCursor().setPosition(pos);
//            QTextCharFormat charFormat = edit->textCursor().charFormat();
//        }

        bool isChecked = ui->blodAction->isChecked();

        QTextCharFormat format;
        format.setFontWeight(isChecked ? QFont::Bold : QFont::Normal);     //设置字体粗细

        edit->mergeCurrentCharFormat(format);    //对选中文本合并字符属性格式
    }
}

void MainWindow::on_italicAction_triggered()
{
    TextEdit* edit = activateWindow();
    if(edit)
    {
        QTextCharFormat format;
        format.setFontItalic(ui->italicAction->isChecked());    //设置斜体

        edit->mergeCurrentCharFormat(format);
    }
}

void MainWindow::on_underLineAction_triggered()
{
    TextEdit* edit = activateWindow();
    if(edit)
    {
        QTextCharFormat format;
        format.setFontUnderline(ui->underLineAction->isChecked());       //设置下划线

        edit->mergeCurrentCharFormat(format);
    }
}

void MainWindow::on_leftAlignAction_triggered()
{
    TextEdit* edit = activateWindow();
    if(edit)
    {
//        QTextCursor cursor = edit->textCursor();        //获取当前可见游标的副本
//        QTextBlockFormat textBlockFormat = cursor.blockFormat();       //返回游标所在块的块格式
//        textBlockFormat.setAlignment(Qt::AlignLeft);   //设置段落的对齐方式
//        cursor.mergeBlockFormat(textBlockFormat);      //用textBlockFormat指定的块格式修改当前块(或包含在选择中的所有块)的块格式
//        edit->setTextCursor(cursor);                   //设置可见游标

        edit->setAlignment(Qt::AlignLeft);       //设置光标所在段落(或包含在选择中的所有段落)的对齐方式
    }
}

void MainWindow::on_centerAction_triggered()
{
    TextEdit* edit = activateWindow();
    if(edit)
    {
        edit->setAlignment(Qt::AlignCenter);
    }
}

void MainWindow::on_rightAlignAction_triggered()
{
    TextEdit* edit = activateWindow();
    if(edit)
    {
        edit->setAlignment(Qt::AlignRight);
    }
}

void MainWindow::on_justifyAction_triggered()
{
    TextEdit* edit = activateWindow();
    if(edit)
    {
        edit->setAlignment(Qt::AlignJustify);
    }
}

void MainWindow::on_comboBox_activated(int index)
{
    TextEdit* edit = activateWindow();
    if(edit)
    {
        if(index == 0)
        {
            QTextCursor cursor = edit->textCursor();  // 获取当前textEdit可见游标的副本

            // 指示文档上的编辑操作块的开始，从撤销/重做的角度来看，这些操作块应为单个操作
            cursor.beginEditBlock();  // 编辑开始

            // 检查当前光标是否在列表中
            QTextList* list = cursor.currentList();
            if (list)
            {
                //把包含游标的块从列表中移除
                list->remove(cursor.block());
                QTextBlockFormat blockFormat = cursor.blockFormat();
                blockFormat.setIndent(0);                //重置块的缩进
                cursor.setBlockFormat(blockFormat);      //设置游标所在块（或选择内容包含的所有块）的块格式
            }
            cursor.endEditBlock();  // 编辑结束
            return;
        }

        QTextListFormat::Style style;       //用于描述装饰列表项符号的枚举
        switch(index)
        {
        case 1:
            style = QTextListFormat::ListDisc;        //黑色实心圆
            break;
        case 2:
            style = QTextListFormat::ListCircle;      //空心圆
            break;
        case 3:
            style = QTextListFormat::ListSquare;      //实心方块
            break;
        case 4:
            style = QTextListFormat::ListDecimal;     //升序排列的十进制值
            break;
        case 5:
            style = QTextListFormat::ListLowerAlpha;   //小写字母
            break;
        case 6:
            style = QTextListFormat::ListUpperAlpha;   //大写字母
            break;
        case 7:
            style = QTextListFormat::ListLowerRoman;   //小写罗马字母
            break;
        case 8:
            style = QTextListFormat::ListUpperRoman;   //大写罗马字母
            break;
        default:
            style = QTextListFormat::ListStyleUndefined;  //0
            break;
        }
        QTextCursor cursor = edit->textCursor();        //获取当前textEdit可见游标的副本

        //指示文档上的编辑操作块的开始，从撤销/重做的角度来看，这些操作块应为单个操作
        cursor.beginEditBlock();        //编辑开始

        QTextBlockFormat blockFormat = cursor.blockFormat();    //返回游标所在块的块格式
        QTextListFormat listFormat;        //为列表提供格式信息

        //列表包含一系列文本块，每个文本块都用项目符号或其他符号标记
        QTextList* list = cursor.currentList();      //如果当前游标位置在属于列表的块内，则返回当前列表
        if(list)
        {
            listFormat = list->format();
            list->remove(cursor.block());
            //qDebug() << blockFormat.indent();

            blockFormat.setIndent(0);
            cursor.setBlockFormat(blockFormat);
        }
//        else
//        {
//            listFormat.setIndent(blockFormat.indent() + 1);
//        }

        listFormat.setStyle(style);     //设置列表标号风格
        cursor.createList(listFormat);  //通过传入的列表格式创建一个新列表

        cursor.endEditBlock();          //编辑结束
    }
}

void MainWindow::on_fontComboBox_activated(const QString &arg1)
{
    TextEdit* edit = activateWindow();
    if(edit)
    {
        QTextCharFormat format;
        format.setFontFamily(arg1);

        edit->mergeCurrentCharFormat(format);       //对选中文本合并字符属性格式
    }
}

void MainWindow::on_sizeComboBox_activated(const QString &arg1)
{
    TextEdit* edit = activateWindow();
    if(edit)
    {
        QTextCharFormat format;
        format.setFontPointSize(arg1.toInt());

        edit->mergeCurrentCharFormat(format);         //对选中文本合并字符属性格式
    }
}
